package com.str.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.github.pagehelper.util.StringUtil;
import com.str.dao.SystemMenuDao;
import com.str.dao.SystemRoleDao;
import com.str.dao.SystemUserDao;
import com.str.dao.SystemUserRoleDao;
import com.str.dto.*;
import com.str.pojo.SystemMenu;
import com.str.pojo.SystemRole;
import com.str.pojo.SystemUser;
import com.str.pojo.SystemUserRole;
import com.str.service.SystemUserService;
import com.str.utils.*;
import com.str.vo.*;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * 系统用户信息表(SystemUser)表服务实现类
 *
 * @author makejava
 * @since 2023-04-09 17:59:43
 */
@Service("systemUserService")
@Log4j2
public class SystemUserServiceImpl implements SystemUserService {

    @Resource
    private SystemUserDao systemUserDao;

    @Resource
    private SystemUserRoleDao systemUserRoleDao;

    @Resource
    private RedisUtil redisUtil;

    @Resource
    private SendSmsUtils sendSmsUtils;

    @Resource
    private SystemRoleDao systemRoleDao;

    @Resource
    private SystemMenuDao systemMenuDao;

    /**
     * 获取登录加密key
     *
     * @param requestJson
     * @return
     */
    @Override
    public String getKey(JSONObject requestJson) {
        String phone = requestJson.getString("phone");
        if (StringUtils.isBlank(phone)) {
            return CommonUtil.returnJson(Retcode.PARAM_ERROR.code(), String.format(Retcode.PARAM_ERROR.msg(), "手机号码不能为空"), null);
        }
        try {
            String key = CommonUtil.uuid().substring(0, 16);
            redisUtil.set(phone + "_loginKey", key, 1800000);
            return CommonUtil.returnJson(Retcode.SUCCESS.code(), Retcode.SUCCESS.msg(), key);
        } catch (Exception e) {
            log.error("获取登录加密key Exception", e);
            return CommonUtil.returnJson(Retcode.SYSTEM_EXCEPTION.code(), Retcode.SYSTEM_EXCEPTION.msg(), null);
        }
    }

    /**
     * 登录提交
     *
     * @param loginSubmitDto
     * @return
     */
    @Override
    public String loginSubmit(LoginSubmitDto loginSubmitDto) {
        //从数据库获取用户信息
        SystemUser systemUser = systemUserDao.selectOne(new QueryWrapper<SystemUser>()
                .eq("user_phone", loginSubmitDto.getPhone())
                .ne("user_status", 0));
        //不能存在该用户
        if (Objects.isNull(systemUser)) {
            return CommonUtil.returnJson(Retcode.USER_NON_EXISTENT.code(), Retcode.USER_NON_EXISTENT.msg(), null);
        }
        //账户已被冻结
        if (systemUser.getUserStatus() == Constant.FROZEN_STATE) {
            return CommonUtil.returnJson(Retcode.LOGIN_FAIL_FROZEN.code(), Retcode.LOGIN_FAIL_FROZEN.msg(), null);
        }
        // 查询用户24小时内连续输错次数
        String loginFailCountKey = loginSubmitDto.getPhone() + "_login_fail_count";
        int loginFailCount = 0;
        if (redisUtil.hasKey(loginFailCountKey)) {
            loginFailCount = redisUtil.get(loginFailCountKey, Integer.class);
        }
        // 超过规定的次数，修改用户状态为已冻结
        if (loginFailCount >= Constant.LOGIN_FAIL_COUNT) {
            systemUser.setUserStatus(2);
            systemUserDao.update(systemUser, new QueryWrapper<SystemUser>().eq("user_id", systemUser.getUserId()));
            return CommonUtil.returnJson(Retcode.LOGIN_FAIL_FROZEN.code(), Retcode.LOGIN_FAIL_FROZEN.msg(), null);
        }
        //1、密码登录
        if (loginSubmitDto.getLoginType() == Constant.LOGIN_TYPE_PD) {
            // 获取加密秘钥
            String key = redisUtil.get(loginSubmitDto.getPhone() + "_loginKey", String.class);
            if (StringUtils.isBlank(key)) {
                return CommonUtil.returnJson(Retcode.LOGIN_KEY_TIMEOUT.code(), Retcode.LOGIN_KEY_TIMEOUT.msg(), null);
            }
            //todo (测试使用，后续一定要删除！！！！)
            // String encrypt = AesUtils.encrypt(loginSubmitDto.getPassword(), key);
            // 解密密码
            if (StringUtil.isNotEmpty(loginSubmitDto.getPassword()) || !"null".equals(loginSubmitDto.getPassword())) {
                //解密用户输入密码
                // String password = AesUtils.decrypt(encrypt, key);
                String password = AesUtils.decrypt(loginSubmitDto.getPassword(), key);
                redisUtil.del(loginSubmitDto.getPhone() + "_loginKey");
                if (StringUtils.isBlank(password)) {
                    return CommonUtil.returnJson(Retcode.LOGIN_DECRYPT_ERROR.code(), Retcode.LOGIN_DECRYPT_ERROR.msg(), null);
                }
                //解密用户数据库密码
                String pwdKey = AesUtils.loginPwdKey(systemUser.getUserId());
                String parsePassword = AesUtils.decrypt(systemUser.getPassword(), pwdKey);
                if (!Objects.equals(password, parsePassword)) {
                    // 把输入错误次数放入redis中
                    loginFailCount = loginFailCount + 1;
                    redisUtil.set(loginFailCountKey, loginFailCount, 24 * 60 * 60);
                    // 超过规定的次数，修改用户状态为已冻结
                    if (loginFailCount >= Constant.LOGIN_FAIL_COUNT) {
                        systemUserDao.update(systemUser, new QueryWrapper<SystemUser>().eq("user_id", systemUser.getUserId()));
                        return CommonUtil.returnJson(Retcode.LOGIN_FAIL_FROZEN.code(), Retcode.LOGIN_FAIL_FROZEN.msg(), null);
                    }
                    return CommonUtil.returnJson(Retcode.LOGIN_FAIL_COUNT.code(), String.format(Retcode.LOGIN_FAIL_COUNT.msg(), Constant.LOGIN_FAIL_COUNT - loginFailCount), null);
                }
            }
        } else if (loginSubmitDto.getLoginType() == Constant.LOGIN_TYPE_CODE) {
            //验证码登录
            //redis获取该手机的短信验证码
            String code = redisUtil.get("login_code_" + loginSubmitDto.getPhone(), String.class);
            if (StringUtil.isNotEmpty(code) && !"null".equals(code)) {
                if (!code.equals(loginSubmitDto.getCode())) {
                    return CommonUtil.returnJson(Retcode.LOGIN_FAIL_CODE.code(), Retcode.LOGIN_FAIL_CODE.msg(), null);
                }
            } else {
                return CommonUtil.returnJson(Retcode.SMS_VERIFY_TIMEOUT.code(), Retcode.SMS_VERIFY_TIMEOUT.msg(), null);
            }
        }
        // 判断是否分配了角色
        SystemUserRole role = systemUserRoleDao.selectOne(new QueryWrapper<SystemUserRole>()
                .eq("user_id", systemUser.getUserId()));
        SystemRole systemRole = systemRoleDao.selectOne(new QueryWrapper<SystemRole>()
                .eq("role_id", role.getRoleId()));
        if (Objects.isNull(role) || Objects.isNull(systemRole)) {
            return CommonUtil.returnJson(Retcode.LOGIN_FAIL_NOT_ROLE.code(), Retcode.LOGIN_FAIL_NOT_ROLE.msg(), null);
        }
        //根据角色查询响应的菜单信息（权限处理）
        List<SystemMenu> menus = systemMenuDao.queryMenuByRoleId(role.getRoleId());
        // 判断有没有在线的，如果有则移除掉（单点登录）
        String loginTokenRedisKey = systemUser.getUserId() + "_login_token";
        String loginToken = redisUtil.get(loginTokenRedisKey, String.class);
        if (StringUtils.isNotEmpty(loginToken)) {
            redisUtil.del(loginToken);
        }
        // 设置token，并移除掉密码，放入缓存中
        String token = CommonUtil.uuid();
        SystemUserVO systemUserVO = CopyUtils.copyObj(systemUser, SystemUserVO.class);
        systemUserVO.setRoleId(systemRole.getRoleId());
        systemUserVO.setRoleName(systemRole.getRoleName());
        systemUserVO.setToken(token);
        systemUserVO.setPassword("");
        systemUserVO.setMenus(menus);
        redisUtil.del(loginFailCountKey);
        int time = 2 * 60 * 60;
        redisUtil.set(loginTokenRedisKey, token, time);
        redisUtil.set(token, systemUserVO, time);
        return CommonUtil.returnJson(Retcode.SUCCESS.code(), Retcode.SUCCESS.msg(), systemUserVO);
    }

    /**
     * 短信验证码登录获取验证码
     *
     * @param requestJson
     * @return
     */
    @Override
    public ResponseVO getLoginCode(JSONObject requestJson) {
        String phone = requestJson.getString("phone");
        String sixBitRandom = "";
        ResponseVO responseVO = new ResponseVO();
        if (StringUtils.isBlank(phone)) {
            return new ResponseVO(Retcode.PARAM_ERROR.code(), String.format(Retcode.PARAM_ERROR.msg(), "手机号码不能为空"), null);
        }
        //从数据库获取用户信息
        SystemUser systemUser = systemUserDao.selectOne(new QueryWrapper<SystemUser>()
                .eq("user_phone", phone)
                .eq("user_status", 1));
        if (Objects.nonNull(systemUser)) {
            //生成随机6位数验证码
            sixBitRandom = RandomUtil.getSixBitRandom();
            //发送短信
            responseVO = sendSmsUtils.verifySmsCode(new SmsCodeVerifyDto()
                    .setCode(sixBitRandom)   //18709185812
                    .setPhoneNumbers(phone));
            //存入redis，设置有效期15分钟
            redisUtil.set("login_code_" + phone, sixBitRandom, 900);

        }else {
            throw new RuntimeException("该用户不存在或账号已被冻结，请联系管理员!");
        }
        return responseVO;
    }

    /**
     * 重置密码
     *
     * @param dto
     * @return
     */
    @Override
    public ResponseVO resetPassword(ResetPasswordDto dto, HttpServletRequest request) {
        //获取登录用户信息
        SystemUserVO loginUser = CommonUtil.getSystemUser(request);
        //验证两次新密码是否输入一致
        if (!Objects.equals(dto.getNewPassword(), dto.getOncePassword())) {
            throw new RuntimeException("两次输入不一致!");
        }
        String oldSqlPassword = null;
        String pwdKey = null;
        SystemUser sqlUser = systemUserDao.selectOne(new QueryWrapper<SystemUser>()
                .eq("user_id", loginUser.getUserId())
                .eq("user_status", 1));
        if (Objects.nonNull(sqlUser)) {
            pwdKey = AesUtils.loginPwdKey(sqlUser.getUserId());
            oldSqlPassword = AesUtils.decrypt(sqlUser.getPassword(), pwdKey);
        }else {
            throw new RuntimeException("该用户不存在或账号已被冻结，请联系管理员!");
        }
        if (!dto.getOldPassword().equals(oldSqlPassword)) {
            throw new RuntimeException("旧密码输入错误!");
        }
        //更新数据库信息
        SystemUser systemUser = new SystemUser();
        systemUser.setPassword(AesUtils.encrypt(dto.getNewPassword(), pwdKey));
        systemUserDao.update(systemUser, new QueryWrapper<SystemUser>()
                .eq("user_id", loginUser.getUserId())
                .eq("user_status", 1));
        //清除token重新登录
        redisUtil.del(systemUser.getUserId() + "_login_token");
        return new ResponseVO("重置密码成功！");
    }

    /**
     * 获取用户列表
     *
     * @param request
     * @return
     */
    @Override
    public ResponseVO getSystemUserList(GetSystemUserListDto dto, HttpServletRequest request) {
        List<SystemUserListVO> list = new ArrayList<>();
        //获取登录用户信息
        SystemUserVO loginUser = CommonUtil.getSystemUser(request);
        if (Objects.equals(loginUser.getRoleName(), Constant.SYSTEM_USER)) {
            //系统管理人员可以获取所有用户信息
            PageHelper.startPage(dto.getPageNum(), dto.getPageSize());
            List<SystemUser> users = systemUserDao.selectList(new QueryWrapper<SystemUser>()
                    .ne("user_status", 0)
                    .like(StringUtil.isNotEmpty(dto.getUserName()), "user_name", dto.getUserName())
                    .eq(StringUtil.isNotEmpty(dto.getUserPhone()), "user_phone", dto.getUserPhone()));
            list = CopyUtils.copyList(users, SystemUserListVO.class);
        }
        return new ResponseVO(new PageInfo<>(list));
    }

    /**
     * 获取用户个人信息
     *
     * @param requestJson
     * @param request
     * @return
     */
    @Override
    public ResponseVO getSystemUser(JSONObject requestJson, HttpServletRequest request) {
        String userId = requestJson.getString("user_id");
        //获取登录用户信息
        SystemUserVO loginUser = CommonUtil.getSystemUser(request);
        SystemUser systemUser = new SystemUser();
        if (StringUtil.isNotEmpty(userId) && !"null".equals(userId)) {
            systemUser = systemUserDao.selectOne(new QueryWrapper<SystemUser>().eq("user_id", userId));
        }
        GetSystemUserVO vo = CopyUtils.copyObj(Objects.nonNull(systemUser) ? systemUser : loginUser, GetSystemUserVO.class);
        return new ResponseVO(vo);
    }

    /**
     * 添加用户
     *
     * @param addSystemUserDto
     * @param request
     * @return
     */
    @Override
    public ResponseVO addSystemUser(AddSystemUserDto addSystemUserDto, HttpServletRequest request) {
        //获取登录用户信息
        SystemUserVO loginUser = CommonUtil.getSystemUser(request);
        if (Objects.equals(loginUser.getRoleName(), Constant.SYSTEM_USER)) {
            SystemUser systemUser = CopyUtils.copyObj(addSystemUserDto, SystemUser.class);
            String uuid = CommonUtil.uuid();
            systemUser.setUserId(uuid);
            systemUser.setCreatedBy(loginUser.getUserName());
            systemUser.setUpdateBy(loginUser.getUserName());
            String pwdKey = AesUtils.loginPwdKey(uuid);
            //设置默认密码
            String password = AesUtils.encrypt("a12345678", pwdKey);
            systemUser.setPassword(password);
            //新增之前判断是否已存在该用户
            SystemUser sqlSystemUser = systemUserDao.selectOne(new QueryWrapper<SystemUser>()
                    .eq("user_phone", systemUser.getUserPhone())
                    .ne("user_status", 0));
            if (Objects.isNull(sqlSystemUser)) {
                int insert = systemUserDao.insert(systemUser);
                if (insert > 0) {
                    return new ResponseVO("添加成功！");
                }
            } else {
                throw new RuntimeException("该用户已存在！");
            }
        } else {
            throw new RuntimeException("非管理人员无法添加用户！");
        }
        return new ResponseVO("添加失败！");
    }

    /**
     * 删除用户
     *
     * @param requestJson
     * @param request
     * @return
     */
    @Override
    public ResponseVO deleteSystemUser(JSONObject requestJson, HttpServletRequest request) {
        String userId = requestJson.getString("user_id");
        //获取登录用户信息
        SystemUserVO loginUser = CommonUtil.getSystemUser(request);
        if (Objects.equals(loginUser.getRoleName(), Constant.SYSTEM_USER)) {
            if (StringUtil.isNotEmpty(userId) && !"null".equals(userId)) {
                SystemUser systemUser = new SystemUser();
                systemUser.setUserStatus(0);
                List<SystemUserRole> userRoleList = systemUserRoleDao.selectList(new QueryWrapper<SystemUserRole>().eq("user_id", userId));
                if (Objects.nonNull(userRoleList) && userRoleList.size() > 0) {
                    systemUserRoleDao.delete(new QueryWrapper<SystemUserRole>().eq("user_id", userId));
                }
                int result = systemUserDao.delete(new QueryWrapper<SystemUser>().eq("user_id", userId));
                if (result > 0) {
                    return new ResponseVO("删除成功！");
                }
            }
        } else {
            throw new RuntimeException("非管理人员无法删除用户！");
        }
        return new ResponseVO("删除失败！");
    }

    /**
     * 启用/冻结
     *
     * @param dto
     * @param request
     * @return
     */
    @Override
    public ResponseVO enableDisableSystemUser(EnableDisableSystemUserDto dto, HttpServletRequest request) {
        //获取登录用户信息
        SystemUserVO loginUser = CommonUtil.getSystemUser(request);
        if (Objects.equals(loginUser.getRoleName(), Constant.SYSTEM_USER)) {
            SystemUser sqlSystemUser = systemUserDao.selectOne(new QueryWrapper<SystemUser>().eq("user_id", dto.getUserId()).ne("user_status", 0));
            if (Objects.isNull(sqlSystemUser)) {
                throw new RuntimeException("该用户不存在！");
            }
            if (dto.getEnableDisable() == Constant.LOGIN_TYPE_PD) {
                //解冻操作
                SystemUser systemUser = new SystemUser();
                systemUser.setUserStatus(1);
                systemUser.setUpdateTime(new Date());
                systemUser.setUpdateBy(loginUser.getUserName());
                int result = systemUserDao.update(systemUser, new QueryWrapper<SystemUser>().eq("user_id", dto.getUserId()));
                if (result > 0) {
                    return new ResponseVO("解冻成功！");
                }
            } else if (dto.getEnableDisable() == Constant.FROZEN_STATE) {
                //冻结操作
                SystemUser systemUser = new SystemUser();
                systemUser.setUserStatus(2);
                systemUser.setUpdateTime(new Date());
                systemUser.setUpdateBy(loginUser.getUserName());
                int result = systemUserDao.update(systemUser, new QueryWrapper<SystemUser>().eq("user_id", dto.getUserId()));
                if (result > 0) {
                    return new ResponseVO("冻结成功！");
                }
            }
        } else {
            throw new RuntimeException("非管理人员无法该操作！");
        }
        return new ResponseVO("操作成功！");
    }

    /**
     * 获取所有的角色信息
     *
     * @param request
     * @return
     */
    @Override
    public ResponseVO getRoleList(HttpServletRequest request) {
        List<GetRoleListVO> vos = new ArrayList<>();
        List<SystemRole> roles = systemRoleDao.selectList(new QueryWrapper<SystemRole>().ne("role_status", 0));
        if (Objects.nonNull(roles) && roles.size() > 0) {
            vos = CopyUtils.copyList(roles, GetRoleListVO.class);
        }
        return new ResponseVO(vos);
    }

    /**
     * 根据角色类型分页查询绑定角色的正常用户列表
     *
     * @param dto
     * @param request
     * @return
     */
    @Override
    public ResponseVO getRoleUserList(GetRoleUserListDto dto, HttpServletRequest request) {
        List<SystemUserListVO> list = new ArrayList<>();
        //获取登录用户信息
        SystemUserVO loginUser = CommonUtil.getSystemUser(request);
        if (Objects.equals(loginUser.getRoleName(), Constant.SYSTEM_USER)) {
            PageHelper.startPage(dto.getPageNum(), dto.getPageSize());
            list = systemUserRoleDao.getRoleUserList(dto.getRoleId(), dto.getUserName(), dto.getUserPhone());
        } else {
            throw new RuntimeException("非管理人员无法该操作！");
        }
        return new ResponseVO(new PageInfo<>(list));
    }

    /**
     * 删除对应角色的用户
     *
     * @param dto
     * @param request
     * @return
     */
    @Override
    public ResponseVO deleteRoleUser(DeleteRoleUserDto dto, HttpServletRequest request) {
        //获取登录用户信息
        SystemUserVO loginUser = CommonUtil.getSystemUser(request);
        if (Objects.equals(loginUser.getRoleName(), Constant.SYSTEM_USER)) {
            SystemUserRole role = systemUserRoleDao.selectOne(new QueryWrapper<SystemUserRole>()
                    .eq("user_id", dto.getUserId())
                    .eq("role_id", dto.getRoleId()));
            if (Objects.nonNull(role)) {
                int delete = systemUserRoleDao.delete(new QueryWrapper<SystemUserRole>()
                        .eq("user_id", dto.getUserId())
                        .eq("role_id", dto.getRoleId()));
                if (delete > 0) {
                    return new ResponseVO("删除成功！");
                }
            }
        } else {
            throw new RuntimeException("非管理人员无法该操作！");
        }

        return new ResponseVO("删除失败！");
    }

    /**
     * 获取所有的非绑定角色用户列表
     *
     * @param dto
     * @return
     */
    @Override
    public ResponseVO getAllGeneralUserList(GetAllGeneralUserListDto dto, HttpServletRequest request) {
        List<SystemUserListVO> list = new ArrayList<>();
        //获取登录用户信息
        SystemUserVO loginUser = CommonUtil.getSystemUser(request);
        if (Objects.equals(loginUser.getRoleName(), Constant.SYSTEM_USER)) {
            PageHelper.startPage(dto.getPageNum(), dto.getPageSize());
            list = systemUserRoleDao.getAllGeneralUserList(dto.getUserName(), dto.getUserPhone());
        } else {
            throw new RuntimeException("非管理人员无法该操作！");
        }
        return new ResponseVO(new PageInfo<>(list));
    }

    /**
     * 添加对于角色用户信息
     *
     * @param dto
     * @param request
     * @return
     */
    @Override
    public ResponseVO addRoleUserList(AddRoleUserListDto dto, HttpServletRequest request) {
        //获取登录用户信息
        SystemUserVO loginUser = CommonUtil.getSystemUser(request);
        if (Objects.equals(loginUser.getRoleName(), Constant.SYSTEM_USER)) {
            //先判断是否存在该角色
            SystemRole systemRole = systemRoleDao.selectOne(new QueryWrapper<SystemRole>().eq("role_id", dto.getRoleId()).ne("role_status", 0));
            if (Objects.nonNull(systemRole)) {
                for (String userId : dto.getUserIds()) {
                    SystemUser systemUser = systemUserDao.selectOne(new QueryWrapper<SystemUser>()
                            .eq("user_id", userId)
                            .eq("user_status", 1));
                    if (Objects.isNull(systemUser)) {
                        throw new RuntimeException("该用户不存在！");
                    }
                    SystemUserRole systemUserRole = systemUserRoleDao.selectOne(new QueryWrapper<SystemUserRole>()
                            .eq("role_id", dto.getRoleId())
                            .eq("user_id", userId));
                    if (Objects.nonNull(systemUserRole)) {
                        throw new RuntimeException("该角色下已绑定该用户！");
                    }
                    systemUserRoleDao.insert(new SystemUserRole().setRoleId(systemRole.getRoleId()).setUserId(userId));
                }
            } else {
                throw new RuntimeException("不存在该角色！");
            }

        } else {
            throw new RuntimeException("非管理人员无法该操作！");
        }
        return new ResponseVO("添加成功！");
    }

    /**
     * 退出登录
     *
     * @param request
     * @return
     */
    @Override
    public ResponseVO logOutSystem(HttpServletRequest request) {
        //获取登录用户信息
        SystemUserVO loginUser = CommonUtil.getSystemUser(request);
        if (Objects.isNull(loginUser)) {
            throw new RuntimeException("该用户未登录！");
        } else {
            //清楚当前登录用户的token
            redisUtil.del(loginUser.getUserId() + "_login_token");
            redisUtil.del(loginUser.getToken());
            return new ResponseVO("已退出登录！");
        }
    }
}
